import chisel3._
import chisel3.util._


class addtree0 extends Module {
    val io = IO(new Bundle {
        val idata = Input(Vec(8,UInt(8.W)))
        val odata = Output(UInt(16.W))
    })
    
def add(a: UInt, b: UInt) = a +% b

val vec = io.idata
val sum = vec.reduce(add)

io.odata := sum 

}

class addtree1 extends Module {
    val io = IO(new Bundle {
        val idata = Input(Vec(8,UInt(8.W)))
        val odata = Output(UInt(16.W))
    })
    
def add(a: UInt, b: UInt) = a +& b

val vec = io.idata
val sum = vec.reduceTree(add)

io.odata := sum 

}

class addtree2 extends Module {
    val io = IO(new Bundle {
        val idata = Input(Vec(8,UInt(8.W)))
        val odata = Output(UInt(16.W))
    })
    
def add(a: UInt, b: UInt) = {
	val tmp = RegNext(a +& b)
	tmp
}

val vec = io.idata
val sum = vec.reduceTree(add)

io.odata := sum 

}

class mintree0 extends Module {
    val io = IO(new Bundle {
        val idata = Input(Vec(8,UInt(8.W)))
        val odata = Output(Vec(2,UInt(8.W)))
    })
    
val vec = io.idata

val resFun = vec.zipWithIndex
	.map ((x) => (x._1, x._2.U))
	.reduce((x, y) => (Mux(x._1 < y._1, x._1, y._1), Mux(x._1 < y._1, x._2, y._2)))


io.odata(0) := resFun._1
io.odata(1) := resFun._2

}

class mintree1 extends Module {
    val io = IO(new Bundle {
        val idata = Input(Vec(8,UInt(8.W)))
        val odata = Output(Vec(2,UInt(8.W)))
    })
    
val vec = io.idata

val scalaVector = vec.zipWithIndex
	.map((x) => MixedVecInit(x._1, x._2.U(8.W)))
val resFun2 = VecInit(scalaVector)
	.reduceTree((x, y) => Mux(x(0) < y(0), x, y))

io.odata := resFun2

}





/**
 * An object extending App to generate the Verilog code.
 */
object addtree extends App {
  (new chisel3.stage.ChiselStage).emitVerilog(new addtree0())
  (new chisel3.stage.ChiselStage).emitVerilog(new addtree1())
  (new chisel3.stage.ChiselStage).emitVerilog(new addtree2())
  (new chisel3.stage.ChiselStage).emitVerilog(new mintree0())
  (new chisel3.stage.ChiselStage).emitVerilog(new mintree1())
}





